package com.sxt.server.server;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.sxt.server.init.JT808ChannelInitializer;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.ResourceLeakDetector;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class TCPServer {
	/**
	 * NioEventLoopGroup是一个处理I / O操作的多线程事件循环。 Netty为不同类型的传输提供各种EventLoopGroup实现。
	 * 我们在此示例中实现了服务器端应用程序，因此将使用两个NioEventLoopGroup。
	 * 第一个，通常称为“老板”，接受传入连接。第二个，通常称为“工人”， 一旦老板接受连接并将接受的连接注册到工作人员，就处理被接受连接的流量。
	 * 使用了多少个线程以及它们如何映射到创建的Channels取决于EventLoopGroup实现，甚至可以通过构造函数进行配置。
	 */

	@Value("${netty.port}")
	private int nettyPort;

	@Value("${netty.read-timeout}")
	private int readTimeOut;
	
	
	@Autowired
	private JT808ChannelInitializer jt808ChannelInitializer;
	//
	private EventLoopGroup bossGroup = null;
	//
	private EventLoopGroup workerGroup = null;
	
//	@Autowired
//    @Qualifier("businessGroup")
//    private EventExecutorGroup businessGroup;

	/**
	 * 启动 Netty
	 *
	 * @return
	 * @throws InterruptedException
	 */
	@PostConstruct
	public void start() throws InterruptedException {
		ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.SIMPLE);// 内存泄漏检测 开发推荐PARANOID 线上SIMPLE
		//内存泄漏检测 开发推荐 PARANOID 线上使用默认的SIMPLE即可
        //ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.valueOf(leakDetectorLevel.toUpperCase()));
		/** 针对linux优化 */
		String osName = System.getProperty("os.name");
		/** 配置服务端的NIO线程组 */
		if (osName.equalsIgnoreCase("Linux")) {
			/** 负责服务端接收客户端的连接 */
			this.bossGroup = new EpollEventLoopGroup();
			/** 负责进行SocketChannel的网络读写 */
			this.workerGroup = new EpollEventLoopGroup();
		} else {
			/** 负责服务端接收客户端的连接 */
			this.bossGroup = new NioEventLoopGroup();
			/** 负责进行SocketChannel的网络读写 */
			this.workerGroup = new NioEventLoopGroup();
		}
		// =============================分割线===================================//
		/** Netty启动Nio服务端的辅助类 */
		ServerBootstrap bootstrap = new ServerBootstrap();
		bootstrap.group(this.bossGroup, this.workerGroup);
		/** Linux平台用Epoll模式 **/
		if (osName.equals("Linux")) { // Linux平台用Epoll模式
			bootstrap.channel(EpollServerSocketChannel.class);
		} else {
			bootstrap.channel(NioServerSocketChannel.class);
		}

		bootstrap.childHandler(jt808ChannelInitializer)//不能new ，负责导致JT808ChannelInitializer参数无法注入
				.option(ChannelOption.SO_BACKLOG, 1024) // 服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
				.childOption(ChannelOption.TCP_NODELAY, true)// 立即写出
				.childOption(ChannelOption.SO_KEEPALIVE, true);// 长连接
		

		/** 绑定端口同步操作 */
		ChannelFuture future = bootstrap.bind(this.nettyPort).sync();
		if (future.isSuccess()) {
			log.info("启动 Netty 成功");
		}
	}

	/**
	 * 销毁
	 */
	@PreDestroy
	public void destroy() {
		bossGroup.shutdownGracefully().syncUninterruptibly();
		workerGroup.shutdownGracefully().syncUninterruptibly();
		//businessGroup.shutdownGracefully().syncUninterruptibly();
		log.info("关闭 Netty 成功");
	}
}
